/*
 * *******************************************************************
 *   @项目名称: BHex Android
 *   @文件名称: NetWorkStatus.java
 *   @Date: 18-11-29 下午4:05
 *   @Author: ppzhao
 *   @Description:
 *   @Copyright（C）: 2018 BlueHelix Inc.   All rights reserved.
 *   注意：本内容仅限于内部传阅，禁止外泄以及用于其他的商业目的.
 *  *******************************************************************
 */

package io.bhex.app.utils;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.v4.net.ConnectivityManagerCompat;
import android.telephony.TelephonyManager;

import java.net.InetAddress;
import java.net.UnknownHostException;

import io.bhex.baselib.constant.AppData;

public class NetWorkStatus {

    /**
     * 检查当前WIFI是否连接，两层意思——是否连接，连接是不是WIFI
     *
     * @param context
     * @return true表示当前网络处于连接状态，且是WIFI，否则返回false
     */
    public static boolean isWifiConnected(Context context) {
        boolean bRet = false;
        try {
            if (context == null) {
                return bRet;
            }

            ConnectivityManager cm = (ConnectivityManager) context
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo info = cm.getActiveNetworkInfo();
            if (info != null && info.isConnected()
                    && ConnectivityManager.TYPE_WIFI == info.getType()) {
                return true;
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            bRet = false;
        }

        return bRet;
    }

    /**
     * 检查当前GPRS是否连接，两层意思——是否连接，连接是不是GPRS
     *
     * @param context
     * @return true表示当前网络处于连接状态，且是GPRS，否则返回false
     */
    public static boolean isGprsConnected(Context context) {
        boolean bRet = false;
        try {
            if (context == null) {
                return bRet;
            }

            ConnectivityManager cm = (ConnectivityManager) context
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo info = cm.getActiveNetworkInfo();
            if (info != null && info.isConnected()
                    && ConnectivityManager.TYPE_MOBILE == info.getType()) {
                return true;
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            bRet = false;
        }

        return bRet;
    }

    /**
     * 检查当前是否连接
     *
     * @return true表示当前网络处于连接状态，否则返回false
     */
    public static boolean isConnected(ConnectivityManager cm) {
        boolean bRet = false;
        try {
            if (cm == null) {
                return bRet;
            }

            NetworkInfo info = cm.getActiveNetworkInfo();
            if (info != null && info.isConnected()) {
                return true;
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            bRet = false;
        }

        return bRet;
    }

    /**
     * 检查当前是否连接
     *
     * @param context
     * @return true表示当前网络处于连接状态，否则返回false
     */
    public static boolean isConnected(Context context) {
        boolean bRet = false;
        try {
            if (context == null) {
                return bRet;
            }

            ConnectivityManager cm = (ConnectivityManager) context
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo info = cm.getActiveNetworkInfo();
            if (info != null && info.isConnected()) {
                return true;
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            bRet = false;
        }

        return bRet;
    }

    /**
     * 对大数据传输时，需要调用该方法做出判断，如果流量敏感，应该提示用户
     *
     * @param context
     * @return true表示流量敏感，false表示不敏感
     */
    public static boolean isActiveNetworkMetered(Context context) {
        boolean bRet = false;
        try {
            if (context == null) {
                return bRet;
            }

            ConnectivityManager cm = (ConnectivityManager) context
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
            return ConnectivityManagerCompat.isActiveNetworkMetered(cm);
        } catch (Exception ex) {
            ex.printStackTrace();
            bRet = false;
        }

        return bRet;
    }

    public static void registerReceiver(Context context,
                                        ConnectivityChangeReceiver receiver) {
        try {
            if (context == null || receiver == null) {
                return;
            }

            context.registerReceiver(receiver,
                    ConnectivityChangeReceiver.FILTER);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public static void unregisterReceiver(Context context,
                                          ConnectivityChangeReceiver receiver) {
        try {
            if (context == null || receiver == null) {
                return;
            }

            context.unregisterReceiver(receiver);
        } catch (Exception ex) {
        }
    }

    /**
     * Function: Check Network Type
     *
     * @param context
     * @return
     */
    public static String checkNetworkType(Context context) {
        try {
            ConnectivityManager connectivity = (ConnectivityManager) context
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
            if (connectivity != null) {
                NetworkInfo info = connectivity.getActiveNetworkInfo();
                if (info != null && info.isAvailable()
                        && info.getState() == NetworkInfo.State.CONNECTED) {
                    switch (info.getType()) {
                        case ConnectivityManager.TYPE_WIFI:
                            return "TYPE_WIFI";
                        case ConnectivityManager.TYPE_MOBILE:
                            switch (info.getSubtype()) {
                                case TelephonyManager.NETWORK_TYPE_1xRTT:
                                    return "NETWORK_TYPE_1xRTT"; // 2G ~ 50-100 kbps
                                case TelephonyManager.NETWORK_TYPE_CDMA:
                                    return "NETWORK_TYPE_CDMA"; // 2G ~ 14-64 kbps
                                case TelephonyManager.NETWORK_TYPE_EDGE:
                                    return "NETWORK_TYPE_EDGE"; // 2G ~ 50-100 kbps
                                case TelephonyManager.NETWORK_TYPE_GPRS:
                                    return "NETWORK_TYPE_GPRS"; // 2G ~ 100 kbps
                                case TelephonyManager.NETWORK_TYPE_EVDO_0:
                                    return "NETWORK_TYPE_EVDO_0"; // 3G ~ 400-1000 kbps
                                case TelephonyManager.NETWORK_TYPE_EVDO_A:
                                    return "NETWORK_TYPE_EVDO_A"; // 3G ~ 600-1400 kbps
                                case TelephonyManager.NETWORK_TYPE_EVDO_B:
                                    return "NETWORK_TYPE_EVDO_B"; // 3G ~ 600-1400 kbps
                                case TelephonyManager.NETWORK_TYPE_HSDPA:
                                    return "NETWORK_TYPE_HSDPA"; // 3G ~ 2-14 Mbps
                                case TelephonyManager.NETWORK_TYPE_HSPA:
                                    return "NETWORK_TYPE_HSPA"; // 3G ~ 700-1700 kbps
                                case TelephonyManager.NETWORK_TYPE_HSUPA:
                                    return "NETWORK_TYPE_HSUPA"; // 3G ~ 1-23 Mbps
                                case TelephonyManager.NETWORK_TYPE_UMTS:
                                    return "NETWORK_TYPE_UMTS"; // 3G ~ 400-7000 kbps
                                case TelephonyManager.NETWORK_TYPE_LTE:
                                    return "NETWORK_TYPE_LTE"; // 4G ~ 10+ Mbps
                                case TelephonyManager.NETWORK_TYPE_UNKNOWN:
                                    return "NETWORK_TYPE_UNKNOWN";
                            }
                        case ConnectivityManager.TYPE_MOBILE_DUN:
                            return "TYPE_MOBILE_DUN";
                        case ConnectivityManager.TYPE_MOBILE_HIPRI:
                            return "TYPE_MOBILE_HIPRI";
                        case ConnectivityManager.TYPE_MOBILE_MMS:
                            return "TYPE_MOBILE_MMS";
                        case ConnectivityManager.TYPE_MOBILE_SUPL:
                            return "TYPE_MOBILE_SUPL";
                        case ConnectivityManager.TYPE_WIMAX:
                            return "TYPE_WIMAX";
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
        return "";

    }

    /**
     * Function: Check Network Type
     *
     * @param context
     * @return
     */
    public static int checkNetworkType(Context context, ConnectivityManager cm) {
        int nRet = AppData.Network.NETWORK_TYPE_UNKNOWN;
        try {
            ConnectivityManager connectivity = cm;
            if (connectivity == null && context != null) {
                connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            }

            if (connectivity != null) {
                NetworkInfo info = connectivity.getActiveNetworkInfo();

                if (info == null || !info.isAvailable()
                        || info.getState() != NetworkInfo.State.CONNECTED) {
                    nRet = AppData.Network.NETWORK_TYPE_NO;
                }

//				int 	NETWORK_TYPE_1xRTT 	Current network is 1xRTT
//				int 	NETWORK_TYPE_CDMA 	Current network is CDMA: Either IS95A or IS95B
//				int 	NETWORK_TYPE_EDGE 	Current network is EDGE
//				int 	NETWORK_TYPE_EHRPD 	Current network is eHRPD
//				int 	NETWORK_TYPE_EVDO_0 	Current network is EVDO revision 0
//				int 	NETWORK_TYPE_EVDO_A 	Current network is EVDO revision A
//				int 	NETWORK_TYPE_EVDO_B 	Current network is EVDO revision B
//				int 	NETWORK_TYPE_GPRS 	Current network is GPRS
//				int 	NETWORK_TYPE_HSDPA 	Current network is HSDPA
//				int 	NETWORK_TYPE_HSPA 	Current network is HSPA
//				int 	NETWORK_TYPE_HSPAP 	Current network is HSPA+
//				int 	NETWORK_TYPE_HSUPA 	Current network is HSUPA
//				int 	NETWORK_TYPE_IDEN 	Current network is iDen
//				int 	NETWORK_TYPE_LTE 	Current network is LTE
//				int 	NETWORK_TYPE_UMTS 	Current network is UMTS
//				int 	NETWORK_TYPE_UNKNOWN 	Network type is unknown

                if (info != null && info.isAvailable()
                        && info.getState() == NetworkInfo.State.CONNECTED) {
                    switch (info.getType()) {
                        case ConnectivityManager.TYPE_WIFI:
                            nRet = AppData.Network.NETWORK_TYPE_WIFI;
                            break;
                        case ConnectivityManager.TYPE_MOBILE:
                            switch (info.getSubtype()) {
                                case TelephonyManager.NETWORK_TYPE_1xRTT:
//							return "NETWORK_TYPE_1xRTT"; // 2G ~ 50-100 kbps
                                case TelephonyManager.NETWORK_TYPE_CDMA:
//							return "NETWORK_TYPE_CDMA"; // 2G ~ 14-64 kbps
                                case TelephonyManager.NETWORK_TYPE_EDGE:
//							return "NETWORK_TYPE_EDGE"; // 2G ~ 50-100 kbps
                                case TelephonyManager.NETWORK_TYPE_GPRS:
//							return "NETWORK_TYPE_GPRS"; // 2G ~ 100 kbps
                                    nRet = AppData.Network.NETWORK_TYPE_LOW;
                                    break;
                                case TelephonyManager.NETWORK_TYPE_EVDO_0:
//							return "NETWORK_TYPE_EVDO_0"; // 3G ~ 400-1000 kbps
                                case TelephonyManager.NETWORK_TYPE_EVDO_A:
//							return "NETWORK_TYPE_EVDO_A"; // 3G ~ 600-1400 kbps
                                case TelephonyManager.NETWORK_TYPE_EVDO_B:
//							return "NETWORK_TYPE_EVDO_B"; // 3G ~ 600-1400 kbps
                                    nRet = AppData.Network.NETWORK_TYPE_MID;
                                    break;
                                case TelephonyManager.NETWORK_TYPE_HSDPA:
//							return "NETWORK_TYPE_HSDPA"; // 3G ~ 2-14 Mbps
                                case TelephonyManager.NETWORK_TYPE_HSUPA:
//							return "NETWORK_TYPE_HSUPA"; // 3G ~ 1-23 Mbps
                                case TelephonyManager.NETWORK_TYPE_HSPAP:
//							return "NETWORK_TYPE_HSPAP"; // 3G ~ 1-23 Mbps
                                    nRet = AppData.Network.NETWORK_TYPE_HEIGHT;
                                    break;
                                case TelephonyManager.NETWORK_TYPE_HSPA:
//							return "NETWORK_TYPE_HSPA"; // 3G ~ 700-1700 kbps
                                case TelephonyManager.NETWORK_TYPE_UMTS:
//							return "NETWORK_TYPE_UMTS"; // 3G ~ 400-7000 kbps
                                    nRet = AppData.Network.NETWORK_TYPE_MID;
                                    break;
                                case TelephonyManager.NETWORK_TYPE_LTE:
//							return "NETWORK_TYPE_LTE"; // 4G ~ 10+ Mbps
                                    nRet = AppData.Network.NETWORK_TYPE_HEIGHT;
                                    break;
                                case TelephonyManager.NETWORK_TYPE_UNKNOWN:
                                default:
//							return "NETWORK_TYPE_UNKNOWN";
                                    nRet = AppData.Network.NETWORK_TYPE_YES;
                                    break;
                            }
                            break;
                        case ConnectivityManager.TYPE_WIMAX:
//						return "TYPE_WIMAX";
                            nRet = AppData.Network.NETWORK_TYPE_YES;
                            break;
                        case ConnectivityManager.TYPE_MOBILE_DUN:
//						return "TYPE_MOBILE_DUN";
                        case ConnectivityManager.TYPE_MOBILE_HIPRI:
//						return "TYPE_MOBILE_HIPRI";
                        case ConnectivityManager.TYPE_MOBILE_MMS:
//						return "TYPE_MOBILE_MMS";
                        case ConnectivityManager.TYPE_MOBILE_SUPL:
//						return "TYPE_MOBILE_SUPL";
                        default:
//						return "NETWORK_TYPE_UNKNOWN";
                            nRet = AppData.Network.NETWORK_TYPE_NO;
                            break;
                    }
                }
            }

        } catch (Exception e) {
            nRet = AppData.Network.NETWORK_TYPE_UNKNOWN;
        }

        return nRet;
    }

    public static boolean isConnectionFast(int type, int subType) {
        boolean bRet = false;
        try {
            if (type == ConnectivityManager.TYPE_WIFI) {
                return true;
            } else if (type == ConnectivityManager.TYPE_MOBILE) {
                switch (subType) {
                    case TelephonyManager.NETWORK_TYPE_1xRTT:
                        return false; // ~ 50-100 kbps
                    case TelephonyManager.NETWORK_TYPE_CDMA:
                        return false; // ~ 14-64 kbps
                    case TelephonyManager.NETWORK_TYPE_EDGE:
                        return false; // ~ 50-100 kbps
                    case TelephonyManager.NETWORK_TYPE_EVDO_0:
                        return true; // ~ 400-1000 kbps
                    case TelephonyManager.NETWORK_TYPE_EVDO_A:
                        return true; // ~ 600-1400 kbps
                    case TelephonyManager.NETWORK_TYPE_GPRS:
                        return false; // ~ 100 kbps
                    // case TelephonyManager.NETWORK_TYPE_HSDPA:
                    // return true; // ~ 2-14 Mbps
                    // case TelephonyManager.NETWORK_TYPE_HSPA:
                    // return true; // ~ 700-1700 kbps
                    // case TelephonyManager.NETWORK_TYPE_HSUPA:
                    // return true; // ~ 1-23 Mbps
                    case TelephonyManager.NETWORK_TYPE_UMTS:
                        return true; // ~ 400-7000 kbps
                    // NOT AVAILABLE YET IN API LEVEL 7
                    case TelephonyManager.NETWORK_TYPE_EHRPD:
                        return true; // ~ 1-2 Mbps
                    case TelephonyManager.NETWORK_TYPE_EVDO_B:
                        return true; // ~ 5 Mbps
                    case TelephonyManager.NETWORK_TYPE_HSPAP:
                        return true; // ~ 10-20 Mbps
                    case TelephonyManager.NETWORK_TYPE_IDEN:
                        return false; // ~25 kbps
                    case TelephonyManager.NETWORK_TYPE_LTE:
                        return true; // ~ 10+ Mbps
                    // Unknown
                    case TelephonyManager.NETWORK_TYPE_UNKNOWN:
                        return false;
                    default:
                        return false;
                }
            } else {
                return false;
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            bRet = false;
        }

        return bRet;
    }

    public static abstract class ConnectivityChangeReceiver extends
            BroadcastReceiver {
        public static final IntentFilter FILTER = new IntentFilter(
                ConnectivityManager.CONNECTIVITY_ACTION);

        @Override
        public final void onReceive(Context context, Intent intent) {
            try {
                if (context == null) {
                    return;
                }

                ConnectivityManager cm = (ConnectivityManager) context
                        .getSystemService(Context.CONNECTIVITY_SERVICE);
                NetworkInfo wifiInfo = cm
                        .getNetworkInfo(ConnectivityManager.TYPE_WIFI);
                NetworkInfo gprsInfo = cm
                        .getNetworkInfo(ConnectivityManager.TYPE_MOBILE);

                // 判断是否是Connected事件
                boolean wifiConnected = false;
                boolean gprsConnected = false;
                if (wifiInfo != null && wifiInfo.isConnected()) {
                    wifiConnected = true;
                }
                if (gprsInfo != null && gprsInfo.isConnected()) {
                    gprsConnected = true;
                }
                if (wifiConnected || gprsConnected) {
                    int nNetworkType = checkNetworkType(context, cm);
                    onConnected(nNetworkType, wifiConnected, gprsConnected);
                    return;
                }

                // 判断是否是Disconnected事件，注意：处于中间状态的事件不上报给应用！上报会影响体验
                boolean wifiDisconnected = false;
                boolean gprsDisconnected = false;
                if (wifiInfo == null || wifiInfo != null
                        && wifiInfo.getState() == NetworkInfo.State.DISCONNECTED) {
                    wifiDisconnected = true;
                }
                if (gprsInfo == null || gprsInfo != null
                        && (gprsInfo.getState() == NetworkInfo.State.DISCONNECTED || gprsInfo.getState() == NetworkInfo.State.UNKNOWN)) {
                    gprsDisconnected = true;
                }
                if (wifiDisconnected && gprsDisconnected) {
                    onDisconnected();
                    return;
                }

            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

        protected abstract void onDisconnected();

        protected abstract void onConnected(int networktype, boolean bWifi, boolean bGprs);
    }
}
